//=========================================================================
// Copyright (C) 2024 The C++ Component Model(COMO) Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//=========================================================================

#ifndef __VOTER_SERVER_H__
#define __VOTER_SERVER_H__

#include <pthread.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <signal.h>
#include <unistd.h>
#include "config.h"
#include "voter_message.h"
#include "voter_monitor.h"

#ifdef __cplusplus
extern "C"
{
#endif

#define __DBEUG__

/**
 * This structure represents a connected client. There is very little
 * info about it: the socket descriptor.
 *
 * 文件描述符是操作系统分配给进程的唯一整数，用于标识打开的文件、套接字、管道等资源。在
 * Linux 中，通常第一个打开的文件描述符从 3 开始，因为 0、1 和 2 分别保留给标准输入、输
 * 出和错误（即 stdin、stdout 和 stderr）。
 * socket 函数返回 0 是非常不常见的。除非你之前关闭了标准输入 (close(0))，导致新的文件
 * 描述符被分配为 0。否则，socket 函数正常情况下不会返回 0。
 * fd == 0: 表示当前 socket 是一个 UDP 的客户端。
 */
typedef struct tagVoterClient {
    int     fd;                         // Client socket.
    int     idxDealer;                  // zmtp index
    char    client_ip[INET_ADDRSTRLEN];
    int     client_port;
    char    idVoter[MAX_ID_SIZE];
    struct timespec lastAccessTime;
} VoterClient;

typedef struct tagTransaction {
    uint64_t        idTransaction;              // unique identifier for transaction

    // data from each client
    Int64           data[MAX_CLIENTS];
    BigVotingData   bigVotingData[MAX_CLIENTS]; // 表决数据大小超过8字节，放到这个数组中

    int32_t         cur_data_num;

    DataState       dataState[MAX_CLIENTS];

    int32_t         isBigData;                  // 1 for big data and 0 for size less Int64
    int32_t         lenData;                    // length of big data
    VOTING_RESULT   votingResult;
    Int64           mode;

    struct timespec establishTime;              // 建立时间
} Transaction;

/**
 * This global structure encapsulates the global state of the voter.
 **/
typedef struct tagChatState {
    int32_t      serversock;     // Listening server socket.
    int32_t      serversockUdp;  // UDP server socket.
    int32_t      numclients;     // Number of connected clients right now.
    int32_t      max_client_fd;  // The greatest 'clients' slot populated.

    int32_t      monitorsockUdp; // UDP monitor socket.
    struct sockaddr_in  monitorAddr;

    /**
     * clients 中的数据与 trans_arr[].data 中一数据一一对应
     */
    // Clients are set in the corresponding slot of their socket descriptor.
    VoterClient  clients[MAX_CLIENTS];
    Transaction  trans_arr[MAX_NUM_TRANS];

    // 通常，分布式逻辑时钟的值就是表决事务的唯一标识trans_id
    uint64_t     lamportClock[MAX_NUM_TRANS];   // 分布式逻辑时钟

    /**
     * 当前表决事务在trans_arr中的下标
     * 所谓当前表决事务，就是假如 表决事务ID 是自增型的，ID最大的事务，即最新到来的事务
     *
     * 假如当前来的客户端数据的ID不是最大的，该 ID 数据达到了可表决的数量，这时是可能对
     * 该事务进行表决的，但当前事务不是那个ID代珠的事务。
     */
    int32_t      cur_trans_id;
    uint64_t     cur_idTransaction;             // 当前表决事务的id

    uint64_t     last_Success_idTransaction;    // 上一个成功表决的事务的id

    /**
     * Current number of received data from clients for voting
     * Vote starts when current_data_num reaches MIN_CLIENT; After vote,
     * current_data_num clear to zero for reuse.
     */
    int32_t      current_data_num;

    // 最近一次投票的时间
    struct timespec  lastAccessTime;

    VOTER_OUTPUT_MSG pVoterOutputMsg;

    VOTER_MONITOR_FUN pVoterMonitorFun;

    pthread_mutex_t  mutex;

    char     idVoters[MAX_NUM_VOTERS][MAX_ID_SIZE]; // 参与表决的各个表决器的ID
    int32_t  cur_numVoters;                         // 参与表决的表决器数，通过数据共享协议打过交道的

    /**
     * 非 0 表示暂停运行，如当前进程中有资源已经不满足功能安全计算要求，通过把这个变量
     * 置为非 0 使其停止，但不释放资源。
     */
    volatile sig_atomic_t iKeepPaused;
} ChatState;

VoterClient *CreateClient(int fd, struct sockaddr_in *sa);
int FreeClient(int clientId);
void InitVoter(void);
void CleanIdleClient(void);

int ExtractData(int clientId, VoterMessage *message);
int ExtractBigData(int clientId, VoterMessage *message);
int ProcessProtocol(VoterMessage *message, int bufSize, int clientId, bool needSync);
int Vote(Transaction *trans);
void GetMonitorInfo(char *buf, int sizeOfBuf);
void SendMsgToAllClients(int excluded, char *s, size_t len);
int VoterOutputMsg(char *s, size_t len, int outputTokenOrder, uint64_t token, Transaction *trans);
int32_t GetTransIdx();
bool ValidIdTransaction(uint64_t idTransaction);

int voting_main(void);
int voting_voter_main(void);

void notify_select_exit(uint64_t idTransaction);

#ifdef __cplusplus
}
#endif

#endif // __VOTER_SERVER_H__
